package spynx.desl.runtime.impl;

import java.util.HashMap;
import java.util.Map;

import spynx.desl.runtime.IDataStorage;
import spynx.desl.runtime.IExecutionContext;
import spynx.desl.runtime.IObjectVariable;
import spynx.desl.runtime.IRuntimeEntity;

public class ObjectVariable extends Variable implements IObjectVariable, IRuntimeEntity {

	private String className;
	
	protected class ObjectField implements IDataStorage {
		private String fieldname;
		private int fieldIdx;
		
		public ObjectField(String fieldname) {
			this.fieldname = fieldname;
		}
		
		public ObjectField(int fieldidx) {
			this.fieldIdx = fieldidx;
		}

		@Override
		public Object getValue() {
			return fieldname != null ? get(fieldname) :
					get(fieldIdx);
		}

		@Override
		public void setValue(Object value) {
			if (fieldname != null)
				set(fieldname, value);
			else
				set(fieldIdx, value);
		}

		@Override
		public boolean isReadOnly() {
			return false;
		}

		@Override
		public void setReadOnly(boolean readonly) {
		}
	}
	
	protected Map<String, Object> storage = new HashMap<String, Object>();
	
	public ObjectVariable(String className) {
		this.className = className;
	}
	
	@Override
	public String getClassName() {
		return this.className;
	}

	@Override
	public Iterable<String> getFieldNames() {
		return storage.keySet();
	}

	@Override
	public Object getValue() {
		return this;
	}
	
	public Object get(String fieldname) {
		return storage.get(fieldname);
	}
	
	public void set(String fieldname, Object value) {
		storage.put(fieldname, value);
	}
	
	public boolean hasFieldname(String fieldname) {
		return storage.containsKey(fieldname);
	}
	
	@Override
	public boolean isPersist() {
		return className != null && className.startsWith(".");
	}
	
	@Override
	public Object applyOperator(IExecutionContext context, String operator, Object... args) {
		Object param = context.resolveValue(args[0]);
		switch (operator.charAt(0)) {
		case '.': return hasFieldname((String)param) ? new ObjectField((String)param) : null;
		case '[': return new ObjectField((Integer)param);
		}
		return null;
	}
	
	@Override
	public String toString() {
		return String.format("%s [%s]", getName(), getClassName());
	}
	
	protected Object get(int index) {
		throw new RuntimeException(String.format("'%s' does not support indexing", getName()));
	}
	
	protected void set(int index, Object value) {
		throw new RuntimeException(String.format("'%s' does not support indexing", getName()));
	}
}
